package org.nashua.tt151;

import ipcapture.IPCapture;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import org.nashua.tt151.ServerConnection.ConnectionListener;
import org.nashua.tt151.Target.Slot;
import org.nashua.tt151.libraries.parsers.ProtocolParsing.Command;
import org.nashua.tt151.libraries.parsers.ProtocolParsing.Key;
import org.nashua.tt151.libraries.parsers.ProtocolParsing.StringParser;

import processing.core.PApplet;

public class Driver {
	public static final Image FAIL_SAFE = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY);
	public static void main(String[] args) {
		new Driver(null);
		//new Driver("/screen4.jpg");
	}
	private JFrame frame;
	private JLabel screen;
	private long avg = 0;
	private String ip = "10.1.53.11";
	private ServerConnection server;
	private IPCapture cam;
	private Processor p;
	private double cameraAngle = 0;
	protected LED led = LED.RED;
	public Driver(final String fname) {
		if (fname==null) {
			cam = new IPCapture(new PApplet(), "http://"+ip+"/mjpg/video.mjpg", "FRC", "FRC");
			cam.init(320, 240, IPCapture.RGB);
			cam.start();
		}
		frame = new JFrame(fname==null?"Live "+ip:fname);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JMenuBar mb = new JMenuBar();
		frame.setJMenuBar(mb);
		JMenu ledMenu = new JMenu("LED");
		mb.add(ledMenu);
		for (final String color:new String[]{"Amber", "Blue", "Green", "Red"}) {
			JMenuItem it = new JMenuItem(color);
			it.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					led = LED.get(color);
				}
			});
			ledMenu.add(it);
		}
		screen = new JLabel();
		screen.setIcon(new ImageIcon());
		screen.setPreferredSize(new Dimension(960, 240));
		frame.add(screen);
		frame.pack();
		frame.setResizable(false);
		try {
			server = new ServerConnection(1735, new ConnectionListener(){
				public void onConnect(Socket s) {
					System.out.println("[Connected to "+s.getInetAddress().getHostAddress()+" ("+s+")]");
				}

				public void onDisconnect(Socket s) {
					System.out.println("[Disconnected from "+s.getInetAddress().getHostAddress()+" ("+s+")]");
				}

				public void onDataReceived(Socket s, String msg) {
					//System.out.println("[Message from "+s.getInetAddress().getHostAddress()+" ("+s+")] "+msg);
					if (StringParser.isSend(msg)) {
						if (StringParser.getKey(msg).equals(Key.CamAngle)) {
							cameraAngle = Double.parseDouble(StringParser.getValue(msg));
						}
					} else if (StringParser.isQuery(msg)) {
						if (StringParser.getKey(msg).equals(Key.CamAngle)) {
							Slot slot = Target.Slot.getTargetWithID(Integer.parseInt(StringParser.getArgs(msg)[0]));
							Target targ = getTarget(slot);
							if (targ!=null && Math.abs(targ.cy-p.overlay.getHeight()/2)>2) {
								server.send(StringParser.createMessage(Command.Reply, Key.CamAngle, 
										""+(0.0005*(targ.cy-p.overlay.getHeight()/2)/10), new String[]{"0"}));
							} else {
								server.send(StringParser.createMessage(Command.Reply, Key.CamAngle, "0.00", new String[]{"0"}));
							}
						} else if (StringParser.getKey(msg).equals(Key.Position)) {
							Slot slot = Target.Slot.getTargetWithID(Integer.parseInt(StringParser.getArgs(msg)[0]));
							Target targ = getTarget(slot);
							if (targ!=null) {
								server.send(StringParser.createMessage(Command.Reply, Key.Position, 
										""+targ.distance, new String[]{""+targ.offset}));
							} else {
								server.send(StringParser.createMessage(Command.Reply, Key.Position, "-1", new String[]{"0"}));
							}
						}
					}
				}
			});
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Cannot Listen On Port 1735");
			System.exit(0);
		}
		frame.setVisible(true);
		new java.util.Timer().scheduleAtFixedRate(new java.util.TimerTask() {
			public void run() {
				try {
					if (fname!=null) {
						screen.setIcon(new ImageIcon(update(fname)));
					} else if (!cam.isAlive()) {
						cam = new IPCapture(new PApplet(), "http://"+ip+"/mjpg/video.mjpg", "FRC", "FRC");
						cam.init(320, 240, IPCapture.RGB);
						cam.start();
					} else if (cam.isAvailable()) {
						long start = System.currentTimeMillis();
						try {
							screen.setIcon(new ImageIcon(update(null)));
						} catch (Exception e) {
						}
						long end = System.currentTimeMillis();
						if (avg==0) avg=end-start;
						else avg=(avg+end-start)/2;
						//System.out.println(1000/avg+"fps");
					}
				} catch (NullPointerException e) {					
				}
			}
		}, 1, 33);
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				try {
					if (server!=null) {
						server.disconnect(true);
					}
				} catch (Exception e) {
				}
			}
		});
	}
	private Target getTarget(Slot slot) {
		ArrayList<Target> t = p.targets;
		Target targ = null;
		if (slot.equals(Slot.UNKNOWN) || t.size()==0) {
			
		} else if (slot.equals(Slot.LOWEST)) {
			targ = t.get(0);
		} else if (slot.equals(Slot.BOTTOM)) {
			if (t.get(0).slot.equals(Slot.BOTTOM)) {
				targ = t.get(0);
			}
		} else if (slot.equals(Slot.MIDDLE_LEFT)) {
			if (t.get(0).slot.equals(Slot.MIDDLE)) {
				targ = t.get(0);
			} else if (t.size()>1 && t.get(1).slot.equals(Slot.MIDDLE)) {
				targ = t.get(1);
			}
		} else if (slot.equals(Slot.MIDDLE_RIGHT)) {
			if (t.size()>1 && t.get(1).slot.equals(Slot.MIDDLE)) {
				targ = t.get(1);
			} else if (t.size()>2 && t.get(2).slot.equals(Slot.MIDDLE)) {
				targ = t.get(2);
			}
		} else if (slot.equals(Slot.TOP)) {
			for (int i=t.size()-1; i>-1; i--) {
				if (t.get(i).slot.equals(Slot.TOP)) {
					targ = t.get(i);
					break;
				}
			}
		} else if (slot.equals(Slot.HIGHEST)) {
			targ = t.get(t.size()-1);
		}
		return targ;
	}
	public Image update(String fname) {
		try {
			if (fname!=null) {
				final Image raw = ImageIO.read(Driver.class.getResource(fname));
				p = new Processor(raw, raw.getWidth(null), raw.getHeight(null), cameraAngle, led);
				BufferedImage display = new BufferedImage(raw.getWidth(null)*3, raw.getHeight(null), BufferedImage.TYPE_INT_RGB);
				Graphics g = display.getGraphics();
				g.drawImage(raw, 0, 0, null);
				g.drawImage(p.mask, raw.getWidth(null), 0, null);
				g.drawImage(p.overlay, raw.getWidth(null)*2, 0, null);
				return display;
			} else if (cam.isAvailable()) {
				cam.read();
				final Image raw = cam.getImage();
				p = new Processor(raw, raw.getWidth(null), raw.getHeight(null), cameraAngle, led);
				BufferedImage display = new BufferedImage(raw.getWidth(null)*3, raw.getHeight(null), BufferedImage.TYPE_INT_RGB);
				Graphics g = display.getGraphics();
				g.drawImage(raw, 0, 0, null);
				g.drawImage(p.mask, raw.getWidth(null), 0, null);
				g.drawImage(p.overlay, raw.getWidth(null)*2, 0, null);
				return display;
			}
		} catch (Exception e) {
			
		}
		return null;
	}
}